import { dom, Nodes } from '@knno/dom';
import { PopupPosition, Pos } from '../popup/popup';
import { popMenuStyle } from './popMenu.css';
import { AdaptivePopup } from '../adaptivePopup/adaptivePopup';
import SVGChevronRight from '@mdi/svg/svg/chevron-right.svg';
import SVGCheck from '@mdi/svg/svg/check-bold.svg';

export type RowType = Record<string | number, unknown>;

export type OpenSelectOptions = {
	refer?: Nodes;
	useAction?: boolean;
	// maxShowLines?: number;
	focus?: boolean;
	popupPosition?: PopupPosition | Pos;
	noIndicator?: boolean;
	// width?: number | string;
};

export type SelectCallback = (row: RowType) => void;

export interface SelectHandler {
	close(): void;
	onSelect(callback: SelectCallback): this;
	onClose(callback: () => void): this;
}

type PopMenuOption = {
	/**
	 * if allow children then must both specify expand key and children key
	 */
	children?: number | string;
	/**
	 * if allow children then must both specify expand key and children key
	 */
	icon?: number | string;
	text?: number | string;
	disabled?: number | string;
	line?: number | string;
	checked?: number | string;
};

export class PopMenu {
	static show(
		{ refer, useAction = false, popupPosition = 'bottom-left', noIndicator = false }: OpenSelectOptions,
		data: RowType[],
		{
			text = 'text',
			children = 'children',
			line = 'line',
			disabled = 'disabled',
			icon = 'icon',
			checked = 'checked',
		}: PopMenuOption = {}
	): SelectHandler {
		let onClose: (() => void) | undefined;
		let onSelect: SelectCallback | undefined;
		let subMenuTimeout: NodeJS.Timeout | number | undefined;
		const container = dom
			.div(popMenuStyle)
			.attr('tabIndex', '0')
			.append(
				...data.map((row) => {
					if (row[line]) {
						return dom.div('line');
					} else {
						const iconSpan = dom.span().class('icon');
						const iconStr = row[checked] ? SVGCheck : row[icon];
						const isDisabled = row[disabled];
						const hasChildren = row[children] instanceof Array && row[children].length > 0;
						if (typeof iconStr === 'string') {
							iconSpan.html(iconStr);
						}
						const arrowSpan = dom.span().class('arrow');
						if (hasChildren) {
							arrowSpan.html(SVGChevronRight);
						}
						return dom
							.div('item', ...(isDisabled ? ['disabled'] : []))
							.attr('tabIndex', '0')
							.on('pointerenter', function () {
								this.focus();
							})
							.on('focus', function () {
								if (typeof subMenuTimeout === 'number') clearTimeout(subMenuTimeout);
								Nodes.prototype.removeClass.apply(
									container.query(':scope>div.item').filter((item) => item !== this.elem()),
									['active']
								);
								if (hasChildren && !pop.isAction) {
									openSubMenu(this, row);
								}
							})
							.on('click', function () {
								if (isDisabled) return;
								if (hasChildren) {
									if (pop.isAction) {
										openSubMenu(this, row, 0);
									}
									return;
								}
								pop.close();
								onSelect?.(row);
							})
							.append(
								iconSpan,
								dom
									.span()
									.class('text')
									.text(row[text] + ''),
								arrowSpan
							);
					}
				})
			)
			.on('keydown', (evt) => {
				console.log(evt.key);
				if (evt.key === 'ArrowDown') {
					evt.preventDefault();
					evt.stopPropagation();
					const items = container.query(':scope>div.item').elems() as HTMLElement[];
					const actived = items.findIndex((item) => item === document.activeElement);
					if (actived >= 0) {
						if (actived < items.length - 1) {
							items[actived + 1].focus();
						}
					} else {
						items[0].focus();
					}
				} else if (evt.key === 'ArrowUp') {
					evt.preventDefault();
					evt.stopPropagation();
					const items = container.query(':scope>div.item').elems() as HTMLElement[];
					const actived = items.findIndex((item) => item === document.activeElement);
					if (actived >= 0) {
						if (actived > 0) {
							items[actived - 1].focus();
						}
					} else {
						items[items.length - 1].focus();
					}
				} else if (evt.key === 'Enter') {
					evt.preventDefault();
					evt.stopPropagation();
				}
			});
		const openSubMenu = (lineDiv: Nodes, row: RowType, delay = 300) => {
			subMenuTimeout = setTimeout(() => {
				lineDiv.addClass('active');
				const subMenu = PopMenu.show(
					{ refer: lineDiv, popupPosition: 'right-top', useAction, noIndicator: true },
					row[children] as RowType[]
				);
				subMenu.onClose(() => {
					lineDiv.removeClass('active');
				});
				subMenu.onSelect((subRow) => {
					subMenu.close();
					pop.close();
					onSelect?.(subRow);
				});
			}, delay);
		};
		const pop = AdaptivePopup.show(container, {
			refer,
			popupPosition,
			focus: false,
			useAction,
			width: 'auto',
			noActionBar: true,
			noIndicator,
		})
			.onOpen(() => {
				//l.css('maxHeight', l.getLineHeight() * maxShowLines + 'px').refresh();
				setTimeout(() => {
					container.focus();
				});
			})
			.onClose(() => {
				onClose?.();
			});
		return {
			close() {
				pop.close();
			},
			onSelect(callback) {
				onSelect = callback;
				return this;
			},
			onClose(callback) {
				onClose = callback;
				return this;
			},
		};
	}
}
